let _boundaryCheckingState = true; // 是否进行越界检查的全局开关

/**
 * 把错误的数据转正
 * @private
 * @example strip(0.09999999999999998)=0.1
 */
function strip(num, precision = 15) {
	return +parseFloat(Number(num).toPrecision(precision));
}

/**
 * 返回数字的位数长度
 * @private
 * @param {*number} num Input number
 */
function digitLength(num) {
	// Get digit length of e
	const eSplit = num.toString().split(/[eE]/);
	const len = (eSplit[0].split('.')[1] || '').length - +(eSplit[1] || 0);
	return len > 0 ? len : 0;
}

/**
 * 把小数转成整数,如果是小数则放大成整数
 * @private
 * @param {*number} num 输入数
 */
function float2Fixed(num) {
	if (num.toString().indexOf('e') === -1) {
		return Number(num.toString().replace('.', ''));
	}
	const dLen = digitLength(num);
	return dLen > 0 ? strip(Number(num) * Math.pow(10, dLen)) : Number(num);
}

/**
 * 检测数字是否越界，如果越界给出提示
 * @private
 * @param {*number} num 输入数
 */
function checkBoundary(num) {
	if (_boundaryCheckingState) {
		if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) {
			// console.warn(`${num} 超出了精度限制，结果可能不正确`);
		}
	}
}

/**
 * 把递归操作扁平迭代化
 * @param {number[]} arr 要操作的数字数组
 * @param {function} operation 迭代操作
 * @private
 */
function iteratorOperation(arr, operation) {
	const [num1, num2, ...others] = arr;
	let res = operation(num1, num2);

	others.forEach((num) => {
		res = operation(res, num);
	});

	return res;
}

function transferToNumber(inputNumber) {
      if (isNaN(inputNumber)) {
        return inputNumber
      }
	  
	 if (inputNumber.toString().indexOf('-') == -1) {
	    return inputNumber
	 }
	  
      inputNumber = '' + inputNumber
      inputNumber = parseFloat(inputNumber)
      let eformat = inputNumber.toExponential() // 转换为标准的科学计数法形式（字符串）
      let tmpArray = eformat.match(/\d(?:\.(\d*))?e([+-]\d+)/) // 分离出小数值和指数值
      let number = inputNumber.toFixed(Math.max(0, (tmpArray[1] || '').length - tmpArray[2]))
      return number 
}

/**
 * 高精度乘法
 * @export
 */
export function times(...nums) {
	if (nums.length > 2) {
		return iteratorOperation(nums, times);
	}

	const [num1, num2] = nums;
	const num1Changed = float2Fixed(num1);
	const num2Changed = float2Fixed(num2);
	const baseNum = digitLength(num1) + digitLength(num2);
	const leftValue = num1Changed * num2Changed;

	checkBoundary(leftValue);
	const a = leftValue / Math.pow(10, baseNum)
	return transferToNumber(a);
}

/**
 * 高精度加法
 * @export
 */
export function plus(...nums) {
	if (nums.length > 2) {
		return iteratorOperation(nums, plus);
	}

	const [num1, num2] = nums;
	// 取最大的小数位
	const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
	// 把小数都转为整数然后再计算
	return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
}

/**
 * 高精度减法
 * @export
 */
export function minus(...nums) {
	if (nums.length > 2) {
		return iteratorOperation(nums, minus);
	}

	const [num1, num2] = nums;
	const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
	return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
}

/**
 * 高精度除法
 * @export
 */
export function divide(...nums) {
	if (nums.length > 2) {
		return iteratorOperation(nums, divide);
	}

	const [num1, num2] = nums;
	const num1Changed = float2Fixed(num1);
	const num2Changed = float2Fixed(num2);
	checkBoundary(num1Changed);
	checkBoundary(num2Changed);
	// 重要，这里必须用strip进行修正
	return times(num1Changed / num2Changed, strip(Math.pow(10, digitLength(num2) - digitLength(num1))));
}

/**
 * 四舍五入
 * @export
 */
export function round(num, ratio) {
	const base = Math.pow(10, ratio);
	let result = divide(Math.round(Math.abs(times(num, base))), base);
	if (num < 0 && result !== 0) {
		result = times(result, -1);
	}
	// 位数不足则补0
	return result;
}

/**
 * 是否进行边界检查，默认开启
 * @param flag 标记开关，true 为开启，false 为关闭，默认为 true
 * @export
 */
export function enableBoundaryChecking(flag = true) {
	_boundaryCheckingState = flag;
}

/**
 * @description 样式转换
 * 对象转字符串，或者字符串转对象
 * @param {object | string} customStyle 需要转换的目标
 * @param {String} target 转换的目的，object-转为对象，string-转为字符串
 * @returns {object|string}
 */
function addStyle(customStyle, target = 'object') {
	// 字符串转字符串，对象转对象情形，直接返回
	if (test.empty(customStyle) || typeof(customStyle) === 'object' && target === 'object' || target === 'string' &&
		typeof(customStyle) === 'string') {
		return customStyle
	}
	// 字符串转对象
	if (target === 'object') {
		// 去除字符串样式中的两端空格(中间的空格不能去掉，比如padding: 20px 0如果去掉了就错了)，空格是无用的
		customStyle = trim(customStyle)
		// 根据";"将字符串转为数组形式
		const styleArray = customStyle.split(';')
		const style = {}
		// 历遍数组，拼接成对象
		for (let i = 0; i < styleArray.length; i++) {
			// 'font-size:20px;color:red;'，如此最后字符串有";"的话，会导致styleArray最后一个元素为空字符串，这里需要过滤
			if (styleArray[i]) {
				const item = styleArray[i].split(':')
				style[trim(item[0])] = trim(item[1])
			}
		}
		return style
	}
	// 这里为对象转字符串形式
	let string = ''
	for (const i in customStyle) {
		// 驼峰转为中划线的形式，否则css内联样式，无法识别驼峰样式属性名
		const key = i.replace(/([A-Z])/g, '-$1').toLowerCase()
		string += `${key}:${customStyle[i]};`
	}
	// 去除两端空格
	return trim(string)
}

/**
 * @description 添加单位，如果有rpx，upx，%，px等单位结尾或者值为auto，直接返回，否则加上px单位结尾
 * @param {string|number} value 需要添加单位的值
 * @param {string} unit 添加的单位名 比如px
 */
function addUnit(value = 'auto', unit = uni?.$u?.config?.unit ?? 'px') {
	value = String(value)
	
	// 验证规则中的number判断是否为数值
	return test.number(value) ? `${value}${unit}` : value
}

/**
 * @description 深度克隆
 * @param {object} obj 需要深度克隆的对象
 * @returns {*} 克隆后的对象或者原值（不是对象）
 */
function deepClone(obj) {
	// 对常见的“非”值，直接返回原来值
	if ([null, undefined, NaN, false].includes(obj)) return obj
	if (typeof obj !== 'object' && typeof obj !== 'function') {
		// 原始类型直接返回
		return obj
	}
	const o = test.array(obj) ? [] : {}
	for (const i in obj) {
		if (obj.hasOwnProperty(i)) {
			o[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]
		}
	}
	return o
}

/**
 * @description JS对象深度合并
 * @param {object} target 需要拷贝的对象
 * @param {object} source 拷贝的来源对象
 * @returns {object|boolean} 深度合并后的对象或者false（入参有不是对象）
 */
function deepMerge(target = {}, source = {}) {
	target = deepClone(target)
	if (typeof target !== 'object' || typeof source !== 'object') return false
	for (const prop in source) {
		if (!source.hasOwnProperty(prop)) continue
		if (prop in target) {
			if (typeof target[prop] !== 'object') {
				target[prop] = source[prop]
			} else if (typeof source[prop] !== 'object') {
				target[prop] = source[prop]
			} else if (target[prop].concat && source[prop].concat) {
				target[prop] = target[prop].concat(source[prop])
			} else {
				target[prop] = deepMerge(target[prop], source[prop])
			}
		} else {
			target[prop] = source[prop]
		}
	}
	return target
}


/**
 *
 * @param date    //传入的时间
 * @param fmt     //格式  （yyyy-MM-dd）
 * @returns {*}
 */
export function formatDate(date, fmt) {
	if (/(y+)/.test(fmt)) {
		fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
	}
	let o = {
		'M+': date.getMonth() + 1,
		'd+': date.getDate(),
		'h+': date.getHours(),
		'm+': date.getMinutes(),
		's+': date.getSeconds()
	};
	for (let k in o) {
		if (new RegExp(`(${k})`).test(fmt)) {
			let str = o[k] + '';
			fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str));
		}
	}
	return fmt;
}

function padLeftZero(str) {
	return ('00' + str).substr(str.length);
}


/**
 * 数字转成汉字
 * @params num === 要转换的数字
 * @return 汉字
 * */
export function toChinesNum(num) {
	let changeNum = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
	let unit = ['', '十', '百', '千', '万']
	num = parseInt(num)
	let getWan = (temp) => {
		let strArr = temp.toString().split('').reverse()
		let newNum = ''
		let newArr = []
		strArr.forEach((item, index) => {
			newArr.unshift(item === '0' ? changeNum[item] : changeNum[item] + unit[index])
		})
		let numArr = []
		newArr.forEach((m, n) => {
			if (m !== '零') numArr.push(n)
		})
		if (newArr.length > 1) {
			newArr.forEach((m, n) => {
				if (newArr[newArr.length - 1] === '零') {
					if (n <= numArr[numArr.length - 1]) {
						newNum += m
					}
				} else {
					newNum += m
				}
			})
		} else {
			newNum = newArr[0]
		}

		return newNum
	}
	let overWan = Math.floor(num / 10000)
	let noWan = num % 10000
	if (noWan.toString().length < 4) {
		noWan = '0' + noWan
	}
	return overWan ? getWan(overWan) + '万' + getWan(noWan) : getWan(num)
}


export function formatDuring(mss) {
	if (mss <= 0) return 0
	var days = parseInt(mss / (1000 * 60 * 60 * 24));
	var hours = parseInt((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
	var minutes = parseInt((mss % (1000 * 60 * 60)) / (1000 * 60));
	var seconds = (mss % (1000 * 60)) / 1000;
	// days + " 天 " + hours + " 小时 " + minutes + " 分钟 " + seconds + " 秒 ";
	return {
		day: days,
		hour: hours,
		minute: minutes,
		second: seconds
	}
}

/**
 * 小数位保留
 * @param num    //当前数
 * @param digit  //保留位数
 * @param adapt  //是否补0
 * @returns {number}
 */
export function integer(num, digit, adapt = !digit) {
	num = num || 0;
	digit = digit || 2;
	let strNum = num.toString().split(".");
	if (strNum.length == 1) {
		strNum.push('00000000000000000000000000000000000')
	} else {
		strNum[1] = strNum[1] + '00000000000000000000000000000000000';
	}
	if (adapt) {
		strNum = transferToNumber(parseFloat(strNum[0] + '.' + strNum[1].substr(0, digit)));
	} else {
		strNum = strNum[0] + '.' + strNum[1].substr(0, digit);
	}

	return strNum;
}

/**
 * 16进制转换为RGB
 * @param str    //当前数
 * @example  set16ToRgb('#ffffff');   // rgb(255,255,255)
 */
export function set16ToRgb(str){
   var reg = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/
   if(!reg.test(str)){return;}
   let newStr = (str.toLowerCase()).replace(/\#/g,'')
   let len = newStr.length;
   if(len == 3){
       let t = ''
       for(var i=0;i<len;i++){
           t += newStr.slice(i,i+1).concat(newStr.slice(i,i+1))
       }
       newStr = t
   }
   let arr = []; //将字符串分隔，两个两个的分隔
   for(var i =0;i<6;i=i+2){
       let s = newStr.slice(i,i+2)
       arr.push(parseInt("0x" + s))
   }
   return 'rgb(' + arr.join(",")  + ')';
}
/**
 * RGB转换为16进制
 * @param str    //当前数
 * @example  setRgbTo16('rgb(255,255,255)');   // #ffffff
 */
export function  setRgbTo16(str){
    let reg = /^(rgb|RGB)/;
    if(!reg.test(str)){return;}
    var arr = str.slice(4, str.length-1).split(",")
    let color = '#';
    for(var i=0;i<arr.length;i++){
         var t = Number(arr[i]).toString(16)
         if(t == "0"){   //如果为“0”的话，需要补0操作,否则只有5位数
             t =  t + "0"
         }
         color += t;
    }
    return color;
}



export default {
	times,
	plus,
	minus,
	divide,
	round,
	enableBoundaryChecking,
	addStyle,
	addUnit,
	deepClone,
	deepMerge,
	formatDate,
	toChinesNum,
	formatDuring,
	integer,
	set16ToRgb,
	setRgbTo16
};
